
/**
 * 消息实体 
 * 包括id（唯一生成算法）
 * 
 * */

const CHARS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".split("")

/**设置超时时间*/
const MESSAGE_TIME_OUT=5000

 /**随机生成n位文件名 */
const randomName=(n)=>{
   
    let res=""
    for(let i=0;i<n;i++){
      let id=Math.floor(Math.random()*58)
      res+=CHARS[id]
    }
 
    return res
 
 }

 const generateMId=()=>{
     const name=randomName(6)
     if(Message.room.id) return `${Message.room.id}_${name}`
     else return name
 }


/**
 * 消息暂存队列(发送前/后)
 * 数据格式为{messageId:[]}
 * 
 * 定义消息状态
 * 0 初始化
 * 1 发送中
 * 2 发送成功
 * -1 超时
 * -2 失败
 * 
 * 消息类型
 * 
 * 0 默认 文本
 * 1 图片
 * 2 语音
 * 3 视频
 * 
 */

const Socket =require('./websocket')


export default class Message{

    /**
    * 在发送之前的相关检测
    * 检查对应roomId是否合法
    *  */
   static checkMessageValid(Msg){
      //如果发送该消息的roomId不在当前全局rooms下面则表示非法
      if(!Socket.rooms[Msg.roomId])  return  

      return true
      
   }

   /**通用查找消息的index的方法
    * 返回index
    */
   static findIndex(arr,id){
     if(!Array.isArray(arr)) return 
     for(var i=0,l=arr.length;i<l;i++)
     if(arr[i].id&&arr[i].id===id) return i
   }

   /**
    * 删除数组中对应的某一项
    * 第二个参数为实体
    *  */
   static remove(arr,item){
    if(!Array.isArray(arr)) return 
    for(var i=0,l=arr.length;i<l;i++)
    if(arr[i].id&&item.id&&arr[i].id===item.id) {
        arr.splice(arr,i,1)
        return
    }
   }



       /**
     * 消息握手确认（接收消息的一种） 静态方法
     * 正常需要从暂存队列中将其状态置为发送成功并移除
     * 异常 超时，则拦截不做处理
     * 接收参数为Message实体类(参数转换在socket层处理)
     * */
    static receivehands(Msg){

        /**分两种
         * 一种是已发消息的握手回应
         * 一种是新消息(send_queue中不存在)
         *  */
        if(!Msg.id||!this.checkMessageValid(Msg)) return 

        /**以下为处理握手 */

        /**查找对应的send_queue的该条消息的状态 */
        let message=Socket.rooms[Msg.roomId].send_queue.filter(it=>it.id===Msg.id)
        if(!message.length) return //此时已经超时被删除send_queue队列
        message=message[0]

        /**抛开定时器之外，其实还可以根据发送时间和接受时间来处理，但无法处理超时回调*/
        if(message.status==-1) return //该条消息已经超时，则过滤掉
        message.status=2 
        /**删除send_queue队列中的某项， */
        this.remove(Socket.rooms[Msg.roomId].send_queue,message)
        /**添加到sum_queue */
        Socket.rooms[Msg.roomId].sum_queue.unshift(message)
    
    }

   /**
    * 正常的接收新消息
    * 需要区分当前场景，即在聊天室，还是列表等其他场景，通过Socket.current
    * 
    * 可能存在批量未读消息的处理(暂定未读消息为多条，且不是合并发送)
    *  */ 
   static receiveMsg(Msg){
    
       if(!Msg.roomId) return 

       /**
        * 对应列表情况下消息的提醒以及UI的更新
        * 实际情况下，如果打开的当前聊天室并非Msg对应的roomId场景也需要暂存待处理
        */
       if(!Socket.currentRoom||Socket.currentRoom.id!==Msg.roomId){  
        /**将其加入对应room的待处理消息队列 wait_queue */

        if(!Socket.rooms[Msg.roomId]){  //接收到的新消息对应room不存在当前rooms中，此时理论上要新添加一个room(后台可靠的话)
           Socket.addRoom(Msg.roomId)

        }else{ //将消息存储在wait_queue
          

        }
        /**if和else均要将消息添加到对应未处理队列中 */ 
        Socket.rooms[Msg.roomId].wait_queue.unshift(Msg)
        /**可能需要对应UI更新 */

       }else{ //对应聊天室的消息处理，UI展示渲染


       }

   } 
 


    /**消息必须所属唯一room */
    constructor(options){
      this.id=generateMId()
      this.msg=options.msg
      this.roomId=options.roomId

      this.sendUserId=options.sendUserId||null //消息的发送者 

      /**设置消息默认状态 */
      this.type=options.type||0 //消息类型
      this.status=0
      this.timer=null
      this.sendTime=new Date().getTime() //记录发送时间
    }


    /**接收发送失败的异常处理回调 */
    send(cb){
       if(!this.checkMessageValid(this)) return 

       this.status=1
       Socket.rooms[this.roomId].send_queue.unshift(this) //添加至已发送消息暂存队列

       this.timer=setTimeout(()=>{
          if(this.status!==2){ //未接收到则表示超时，后续也不接收这个id的数据
            this.status=-1  //需要通知回调处理超时情况(这个时候send_queue会自动同步)
            Socket.rooms[this.roomId].fail_queue.unshit(this) //添加到失败队列
            this.remove(Socket.rooms[this.roomId].send_queue,this) //删除对应在发送中的队列

            cb&&cb(this) //处理视图层的回调，一般统一处理重发等
          }
          clearTimeout(this.timer) 
       },MESSAGE_TIME_OUT) 
    }



    /**
     * 设置Message的room
     * 即message绑定在唯一room下
     *  */
    setRoom(id){
      
    }

}